//
// Created by Administrator on 2020/11/10.
//

#include "l1Dl.h"
#include "../../../../o5gran/lcore/include/commMsg.h"
#include "../../../../o5gran/lcore/include/l1ApiMsg.h"

void UE_L1_DL_ProcRanL1DlTtiReq(S_VarRingBuffer *pDlTtiBuff, S_RanCommMsgHdr *pCommMsgHdr)
{
    int32_t rc;
    uint32_t loop;
    S_RanL1ApiMsgDlTtiReq *pDlTtiReq;
    S_UeL1ApiMsgRxDataInd rxDataInd;
    S_UeL1ApiMsgRxDataPdu *pRxDataPdu;

    rxDataInd.commMsgHdr.type = UE_L1_API_MSG_RX_DATA_IND;
    rxDataInd.commMsgHdr.size = sizeof(rxDataInd);
    rxDataInd.pduNum = 0;

    pDlTtiReq  = (S_RanL1ApiMsgDlTtiReq *)pCommMsgHdr;
    for (loop = 0; loop < pDlTtiReq->pduNum; loop++)
    {
        pRxDataPdu = &rxDataInd.pdus[rxDataInd.pduNum];
        switch (pDlTtiReq->pdus[loop].pduType)
        {
        case RAN_L1_API_DL_TTI_PDU_TYPE_SSB:
        {
            S_UeL1ApiMsgSsbInd ssbInd;
            ssbInd.commMsgHdr.type = UE_L1_API_MSG_SSB_IND;
            ssbInd.commMsgHdr.size = sizeof(ssbInd);
            ssbInd.bchPayload = pDlTtiReq->pdus[loop].pdu.ssbPdu.bchPayload;
            VRB_PUT(rc, pDlTtiBuff, &ssbInd, sizeof(ssbInd));
        }
            break;
        case RAN_L1_API_DL_TTI_PDU_TYPE_PDCCH:
            break;
        case RAN_L1_API_DL_TTI_PDU_TYPE_PDSCH:
            break;
        case RAN_L1_API_DL_TTI_PDU_TYPE_CSI_RS:
            break;
        default:
            break;
        }
    }
}

void UE_L1_DL_RecvDataFromRan(S_UeL1UeInst *pUeInst)
{
    int32_t rc;
    uint32_t type;
    uint32_t size;
    uint32_t count;
    uint32_t sfnSlot;
    S_VarRingBuffer *pDlTtiBuff;
    S_RanCommMsgHdr *pCommMsgHdr;

    // TODO
    O5G_SfnSlot_ToU32(pUeInst->sfn, pUeInst->slot, pUeInst->slotNum, &sfnSlot);
    pDlTtiBuff = pUeInst->pDlTtiBuff[(sfnSlot + 1) % UE_L1_TTI_BUFF_NUM];

    count = 0;
    while (1)
    {
        pCommMsgHdr = VarRB_ReadRequest(pUeInst->pRanUeQue, &size);
        if (NULL == pCommMsgHdr)
        {
            usleep(1000);
            if (count++ > 10000)
            {
                assert(0);
            }
            continue;
        }
        type = pCommMsgHdr->type;

        switch (type)
        {
        case RAN_L1_API_MSG_DL_TTI_REQ:
            UE_L1_DL_ProcRanL1DlTtiReq(pDlTtiBuff, pCommMsgHdr);
            break;
        case RAN_L1_API_MSG_UL_DCI_REQ:
            break;
        case RAN_L1_API_MSG_TX_DATA_REQ:
            break;
        default:
            break;
        }

        VarRB_ReadConsume(pUeInst->pRanUeQue, pCommMsgHdr);

        if (RAN_L1_API_MSG_BUTT == type)
        {
            break;
        }
    }
}

void UE_L1_DL_UeProcess(S_UeL1UeInst *pUeInst)
{
    int32_t rc;
    uint32_t loop;
    S_OsSelectInd indMsg;
    S_UeL1ApiMsgSlotInd slotInd;

    switch (pUeInst->appState)
    {
    case UE_L1_APP_STATE_SYNC:
    {
        int32_t rc;
        uint32_t type;
        uint32_t size;
        uint32_t count;
        uint32_t sfnSlot;
        S_VarRingBuffer *pDlTtiBuff;
        S_RanCommMsgHdr *pCommMsgHdr;
        S_UeL1ApiMsgSsbInd *pSsbInd;

        O5G_SfnSlot_ToU32(pUeInst->sfn, pUeInst->slot, pUeInst->slotNum, &sfnSlot);
        pDlTtiBuff = pUeInst->pDlTtiBuff[sfnSlot % UE_L1_TTI_BUFF_NUM];
        while (1)
        {
            pCommMsgHdr = VarRB_ReadRequest(pDlTtiBuff, &size);
            IF_BREAK(==, NULL, pCommMsgHdr, NO_LOG_MESSAGE);

            switch (pCommMsgHdr->type)
            {
            case UE_L1_API_MSG_SSB_IND:
                pSsbInd = (S_UeL1ApiMsgSsbInd *)pCommMsgHdr;
                CSP_LOG_INF(UE_MD_L1_DL, "UE_L1_DL_UeProcess() recv UE_L1_API_MSG_SSB_IND [%u, %u], bchPayload = %#x\n",
                    pUeInst->sfn, pUeInst->slot, pSsbInd->bchPayload);
                break;
            default:
                break;
            }
            VarRB_ReadConsume(pDlTtiBuff, pCommMsgHdr);
        }

        O5G_SfnSlot_Add(&pUeInst->sfn, &pUeInst->slot, pUeInst->slotNum, 1);
    }
        break;
    case UE_L1_APP_STATE_RUNNING:
    {
        slotInd.commMsgHdr.type = UE_L1_API_MSG_SLOT_IND;
        slotInd.commMsgHdr.size = sizeof(slotInd);
        slotInd.ueIdx = pUeInst->ueIdx;
        slotInd.sfn = pUeInst->sfn;
        slotInd.slot = pUeInst->slot;
        VRB_PUT(rc, pUeInst->pL1L2UpMsgQue, &slotInd, sizeof(slotInd));

        pUeInst->sendTtiIntCount++;

        indMsg.ind = UE_L1_L2_IND_MSG_TTI_INT;
        OS_SelectSend(&pUeInst->ttiIntSelector, &indMsg);

        O5G_SfnSlot_Add(&pUeInst->sfn, &pUeInst->slot, pUeInst->slotNum, 1);

//        CSP_LOG_INF(UE_MD_L1_DL, "UE_L1_CellUpProcess() send UE_L1_API_MSG_SLOT_IND [%u, %u]\n", slotInd.sfn, slotInd.slot);
    }
        break;
    default:
        break;
    }
}

void UE_L1_DL_Process(void)
{
    uint32_t ueLoop;
    S_UeL1UeInst *pUeInst;

    for (ueLoop = 0; ueLoop < UE_UE_INST_NUM_MAX; ueLoop++)
    {
        pUeInst = &gpUeL1Context->ueInst[ueLoop];
        IF_CONTINUE(==, FALSE, pUeInst->inUse, NO_LOG_MESSAGE);

        UE_L1_DL_RecvDataFromRan(pUeInst);
        UE_L1_DL_UeProcess(pUeInst);
    }
}
